第 29 天 !
剩~兩~天~!
昨天已經把整個 redux 的流程給接起來了,
從 store 讀取資料還有用 action 去改變 store , 這些我們大概都展示一次 ,
但是很多操作其實並不侷限在本地端,
比較正確來說,
現在所做的一系列這樣一步接一步的動作,我們稱它為 sync(同步)
,
但總有一些操作是我們不會去等,直接前往下一步動作,但會先設定好操作結束後的相關動作,等它去觸發,我們稱它為 async(非同步)
,
在 redux
要處理 async
, action
跟 reducer
都不能做這部份處理,
我們必須加入 middleware
,
redux 允許我們在這裡處理 async
的相關操作,
那... middleware
會在什麼事後觸發呢?
老樣子, 這是官方提供的流程圖
可以看到當我們的 action
去觸發 dispatch
時候,在之前並不會直接進入 reducer
, 而是會先進入 middleware
去跑一遍之後,再進去 reducer,
加入 middleware
後的流程應該是:
那如何加入 middleware
?
第一先選擇我們要使用的 middleware
,
就是我們今天要介紹的 redux-thunk
,
先來安裝:
yarn add redux-thunk
thunk 的內容很少,
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) =>
(next) =>
(action) => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
....嗯,這就是全部了,
有興趣可以去 thunk 的 github 上看看,
它其實很簡單的去建立了,在 middleware
的 async
操作環境,
看程式碼其實可以知道的是,middleware
提供了幾個參數,
蠻直白的,
getState
,取得 store
的資料,
next
,代表是的這 action
直接往下一個 middleware
走,假如沒有就進去 reducer
,
action
, 當前發送的 action
,
extraArgument
這個是 thunk 2.0
才有的參數,主要一開始設定的時候可以帶入額外的參數給 middleware
再來就是 thunk
只是很簡單的去判斷 action
送進來的是不是 function
,
是的話把 dispatch & getState & extraArgument
帶入到這個 function
也就是說要做 sync 就照原樣送 action ,
想要做 async 就把 action 用成 function,
再來就是把 thunk 塞入 redux 裡,
使用 redux
提供的 applyMiddleware
來把 thunk
塞入 redux
,
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducer';
export default function configureStore() {
return createStore(rootReducer, applyMiddleware(thunk));
}
假如有需要額外塞資訊進去,
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducer';
export default function configureStore(api) {
return createStore(
rootReducer,
applyMiddleware(thunk).withExtraArgument({ api })
);
}
這樣 thunk
就進入到 redux
流程裡了,
我們試著把 TodoList
的 新增用 thunk
實作
const fakeAsync = payload => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(payload);
}, 3000);
});
};
export const insertToDoThunk = payload => {
return async dispatch => {
const item = await fakeAsync(payload);
dispatch(insertToDoAction(item));
};
};
因為我們沒有 api 所以設定一個 fakeAsync
來模擬 async,
那流程是 呼叫 insertToDoThunk
會延遲 3 秒,
之後讓 dispatch 執行 insertToDoAction
在 Header component
把 insertToDoAction
換成 insertToDoThunk
結果是: